package org.odk.collect.android.widgets;

import java.util.Date;

import org.javarosa.core.model.data.DateData;
import org.javarosa.core.model.data.IAnswerData;
import org.javarosa.form.api.FormEntryPrompt;
import org.joda.time.Chronology;
import org.joda.time.DateTime;
import org.joda.time.chrono.EthiopicChronology;
import org.joda.time.chrono.GregorianChronology;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.odk.collect.android.R;

import android.content.Context;
import android.content.res.Resources;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

/**
 * Displays a EthiopicDatePicker widget. EthiopicDateWidget allow users to select dates in Ethiopic date format,
 * but what gets sent to the database is the Gregorian equivalent.
 * 
 * @author Alex Little (alex@alexlittle.net)
 */
public class EthiopicDateWidget extends QuestionWidget {

	    private EditText txtMonth;
	    private EditText txtDay;
	    private EditText txtYear;
	    private TextView txtGregorian;
	    
	    private Chronology chron_eth = EthiopicChronology.getInstance();
	    private String[] monthsArray;

	    public EthiopicDateWidget(Context context, FormEntryPrompt prompt) {
	        super(context, prompt);
     
	        Resources res = getResources();
	        monthsArray = res.getStringArray(R.array.tigrinyan_months);
	        
	        LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	        View vv = vi.inflate(R.layout.ethiopic_date_picker, null);
	        addView(vv);
	        
	        
	        txtDay = (EditText) findViewById(R.id.daytext);
            txtMonth = (EditText) findViewById(R.id.monthtext);
            txtYear = (EditText) findViewById(R.id.yeartext);
            txtGregorian = (TextView) findViewById(R.id.dateGregorian);
            
	        Button btnDayUp = (Button) findViewById(R.id.dayupbutton);
            
            btnDayUp.setOnClickListener(new View.OnClickListener() {
				
				@Override
				public void onClick(View arg0) {
					if(txtDay.getText().toString().equals("") || txtDay.getText().toString() == null){
						// if the year field is currently blank set to current day
						DateTime dt = new DateTime();
				    	DateTime dtEthio = dt.withChronology(chron_eth);
						txtDay.setText(String.format("%02d",dtEthio.getDayOfMonth()));
					} else {
						// before validating date, check that the fields contain valid values, otherwise just increment the day
						try {
							Integer.parseInt(txtDay.getText().toString());
							Integer.parseInt(txtYear.getText().toString());
						} catch (Exception e) {
							int newDay = Math.min(30, Integer.parseInt(txtDay.getText().toString())+1);
							txtDay.setText(String.format("%02d",newDay));
							return;
						} 
						int newDay = Integer.parseInt(txtDay.getText().toString())+1;
						if(isValidDate(newDay, 
										getArrayIndex(monthsArray, txtMonth.getText().toString()) +1, 
										Integer.parseInt(txtYear.getText().toString()))){
							txtDay.setText(String.format("%02d",newDay));
						} else if (isValidDate(1, 
								getArrayIndex(monthsArray, txtMonth.getText().toString()) +1, 
								Integer.parseInt(txtYear.getText().toString()))){
							txtDay.setText(String.format("%02d",1));
						}
			    		
					}
					updateDates();
				}
			});
            
            Button btnMonthUp = (Button) findViewById(R.id.monthupbutton);
            
            btnMonthUp.setOnClickListener(new View.OnClickListener() {
				
				@Override
				public void onClick(View arg0) {
					int curr_month = getArrayIndex(monthsArray, txtMonth.getText().toString());
					switch (curr_month){
						case 12:
							txtMonth.setText(monthsArray[0]);
							break;
						case -1:
							DateTime dt = new DateTime();
					    	DateTime dtEthio = dt.withChronology(chron_eth);
							txtMonth.setText(monthsArray[dtEthio.getMonthOfYear()-1]);
							break;
						default:
							// before validating date, check that the fields contain valid values, otherwise just increment the month
							try {
								Integer.parseInt(txtDay.getText().toString());
								Integer.parseInt(txtYear.getText().toString());
							} catch (Exception e) {
								txtMonth.setText(monthsArray[curr_month+1]);
								return;
							} 
							int newMonth = curr_month+2;
							if(isValidDate(Integer.parseInt(txtDay.getText().toString()), 
											newMonth, 
											Integer.parseInt(txtYear.getText().toString()))){
								txtMonth.setText(monthsArray[curr_month+1]);
							} else if(isValidDate(6, 
											newMonth, 
											Integer.parseInt(txtYear.getText().toString()))){
								txtDay.setText(String.format("%02d",6));
								txtMonth.setText(monthsArray[curr_month+1]);
							} else if(isValidDate(5, 
												newMonth, 
												Integer.parseInt(txtYear.getText().toString()))){
								txtDay.setText(String.format("%02d",5));
								txtMonth.setText(monthsArray[curr_month+1]);
							} 
							
							break;
					}
					updateDates();
				}
			});
            
            Button btnYearUp = (Button) findViewById(R.id.yearupbutton);
            
            btnYearUp.setOnClickListener(new View.OnClickListener() {
				
				@Override
				public void onClick(View arg0) {
					if(txtYear.getText().toString().equals("") || txtYear.getText().toString() == null){
						// if field is currently blank, set to current year
						DateTime dt = new DateTime();
				    	DateTime dtEthio = dt.withChronology(chron_eth);
						txtYear.setText(String.format("%04d",dtEthio.getYear()));
					} else {
						// before validating date, check that the fields contain valid values, otherwise just increment the year
						try {
							Integer.parseInt(txtDay.getText().toString());
							Integer.parseInt(txtYear.getText().toString());
						} catch (Exception e) {
							txtYear.setText(String.format("%04d",Integer.parseInt(txtYear.getText().toString())+1));
							return;
						}
						int newYear = Integer.parseInt(txtYear.getText().toString())+1;
						// alter the other fields so it will always result in a valid date
						if(isValidDate(Integer.parseInt(txtDay.getText().toString()), 
										getArrayIndex(monthsArray, txtMonth.getText().toString()) +1,
										newYear)){
							txtYear.setText(String.format("%04d",newYear));
						} else if(isValidDate(5, 
											getArrayIndex(monthsArray, txtMonth.getText().toString()) +1,
											Integer.parseInt(txtYear.getText().toString()))){
							txtDay.setText("5");
							txtYear.setText(String.format("%04d",newYear));
						} 
					}
					updateDates();
				}
			});

            
            Button btnDayDown = (Button) findViewById(R.id.daydownbutton);
            
            btnDayDown.setOnClickListener(new View.OnClickListener() {
				
				@Override
				public void onClick(View arg0) {
					if(txtDay.getText().toString().equals("") || txtDay.getText().toString() == null){
						// if the year field is currently blank set to current day
						DateTime dt = new DateTime();
				    	DateTime dtEthio = dt.withChronology(chron_eth);
						txtDay.setText(String.format("%02d",dtEthio.getDayOfMonth()));
					} else {
						// before validating date, check that the fields contain valid values, otherwise just decrement the day
						try {
							Integer.parseInt(txtDay.getText().toString());
							Integer.parseInt(txtYear.getText().toString());
						} catch (Exception e) {
							int newDay = Math.min(30, Integer.parseInt(txtDay.getText().toString())-1);
							txtDay.setText(String.format("%02d",newDay));
							return;
						} 
						int newDay = Integer.parseInt(txtDay.getText().toString())-1;
						if(isValidDate(newDay, 
								getArrayIndex(monthsArray, txtMonth.getText().toString()) +1, 
										Integer.parseInt(txtYear.getText().toString()))){
							txtDay.setText(String.format("%02d",newDay));
						} else if(isValidDate(30, 
								getArrayIndex(monthsArray, txtMonth.getText().toString()) +1, 
								Integer.parseInt(txtYear.getText().toString()))){
							txtDay.setText(String.format("%02d",30));
						} else if(isValidDate(6, 
								getArrayIndex(monthsArray, txtMonth.getText().toString()) +1, 
								Integer.parseInt(txtYear.getText().toString()))){
							txtDay.setText(String.format("%02d",6));
						} else if(isValidDate(5, 
								getArrayIndex(monthsArray, txtMonth.getText().toString()) +1, 
								Integer.parseInt(txtYear.getText().toString()))){
							txtDay.setText(String.format("%02d",5));
						}
						
					}	
					updateDates();
				}
			});
            
            Button btnMonthDown = (Button) findViewById(R.id.monthdownbutton);

            btnMonthDown.setOnClickListener(new View.OnClickListener() {
				
				@Override
				public void onClick(View arg0) {
					int curr_month = getArrayIndex(monthsArray, txtMonth.getText().toString());
					switch (curr_month){
						case 0:
							// before validating date, check that the fields contain valid values, otherwise just increment the month
							try {
								Integer.parseInt(txtDay.getText().toString());
								Integer.parseInt(txtYear.getText().toString());
							} catch (Exception e) {
								txtMonth.setText(monthsArray[12]);
								return;
							}
							int newMonth = 13;
							if(isValidDate(Integer.parseInt(txtDay.getText().toString()), 
											newMonth, 
											Integer.parseInt(txtYear.getText().toString()))){
								txtMonth.setText(monthsArray[12]);
							} else if(isValidDate(6, 
											newMonth, 
											Integer.parseInt(txtYear.getText().toString()))){
								txtDay.setText(String.format("%02d",6));
								txtMonth.setText(monthsArray[12]);
							} else if(isValidDate(5, 
												newMonth, 
												Integer.parseInt(txtYear.getText().toString()))){
								txtDay.setText(String.format("%02d",5));
								txtMonth.setText(monthsArray[12]);
							} 
							break;
						case -1:
							DateTime dt = new DateTime();
					    	DateTime dtEthio = dt.withChronology(chron_eth);
							txtMonth.setText(monthsArray[dtEthio.getMonthOfYear()-1]);
							break;
						default:
							txtMonth.setText(monthsArray[curr_month-1]);
							break;
					}
					updateDates();
				}
			});

            
            Button btnYearDown = (Button) findViewById(R.id.yeardownbutton);
            
            btnYearDown.setOnClickListener(new View.OnClickListener() {
				
				@Override
				public void onClick(View arg0) {
					if(txtYear.getText().toString().equals("") || txtYear.getText().toString() == null){
						// if the year field is currently blank set to current year
						DateTime dt = new DateTime();
				    	DateTime dtEthio = dt.withChronology(chron_eth);
						txtYear.setText(String.format("%04d",dtEthio.getYear()));
					} else {
						// before validating date, check that the fields contain valid values, otherwise just decrement the year
						try {
							Integer.parseInt(txtDay.getText().toString());
							Integer.parseInt(txtYear.getText().toString());
						} catch (Exception e) {
							txtYear.setText(String.format("%04d",Integer.parseInt(txtYear.getText().toString())-1));
							return;
						} 
						int newYear = Math.max(1, Integer.parseInt(txtYear.getText().toString())-1);
						if(isValidDate(Integer.parseInt(txtDay.getText().toString()), 
								getArrayIndex(monthsArray, txtMonth.getText().toString())+1, 
											newYear)){
							txtYear.setText(String.format("%04d",newYear));
						} else if(isValidDate(5, 
								getArrayIndex(monthsArray, txtMonth.getText().toString())+1, 
											Integer.parseInt(txtYear.getText().toString()))){
							txtDay.setText("5");
							txtYear.setText(String.format("%04d",newYear));
						} 
					}
					updateDates();
				}
			});
	        
	    	// If there's an answer, use it.
	        setAnswer();
	    }


	    private void setAnswer() {

	        if (mPrompt.getAnswerValue() != null) {
	            // setup date object
	            DateTime dtISO = new DateTime(((Date) ((DateData) mPrompt.getAnswerValue()).getValue()).getTime());

	            // find out what the same instant is using the Ethiopic Chronology
	            DateTime dtEthiopic = dtISO.withChronology(chron_eth);
	           
	            txtDay.setText(Integer.toString(dtEthiopic.getDayOfMonth()));
	            txtMonth.setText(monthsArray[dtEthiopic.getMonthOfYear()-1]);
	            txtYear.setText(Integer.toString(dtEthiopic.getYear()));
	            updateDates();
	            
	        } else {
	            // create date widget with current time as of right now
	            clearAnswer();
	        }
	    }


	    /**
	     * Resets date to blank
	     */
	    @Override
	    public void clearAnswer() {
	    	txtDay.setText("");
	    	txtMonth.setText("");
	    	txtYear.setText("");
	    }


	    @Override
	    public IAnswerData getAnswer() {

	    	try {
	    		// Create Ethiopian Date/Time (Y, M, D, H, M, S, mS) 
		    	int ethioDay = Integer.parseInt(txtDay.getText().toString());
		    	int ethioMonth = getArrayIndex(monthsArray, txtMonth.getText().toString()) +1;
		    	int ethioYear = Integer.parseInt(txtYear.getText().toString());
	    	
	    		DateTime dt_eth = new DateTime(ethioYear, ethioMonth, ethioDay, 0, 0, 0, 0, chron_eth);
	    		DateTime dtGregorian = dt_eth.withChronology(GregorianChronology.getInstance());
	    		return new DateData(dtGregorian.toDate());
	    	} catch (Exception e){
	    		//Toast.makeText(getContext(), "Invalid date", Toast.LENGTH_SHORT).show();
	    	}
    		
	    	return null;
	        
	    }


	    @Override
	    public void setFocus(Context context) {
	        // Hide the soft keyboard if it's showing.
	        InputMethodManager inputManager =
	            (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
	        inputManager.hideSoftInputFromWindow(this.getWindowToken(), 0);
	    }


	    @Override
	    public void setOnLongClickListener(OnLongClickListener l) {
	    	
	    }


	    @Override
	    public void cancelLongPress() {
	        super.cancelLongPress();
	    }
	    
	    public boolean isValidDate(int ethioDay, int ethioMonth, int ethioYear){
	    	Chronology chron_eth = EthiopicChronology.getInstance(); 
	    	try {
	    		new DateTime(ethioYear, ethioMonth, ethioDay, 0, 0, 0, 0, chron_eth);
	    		return true;
	    	} catch (Exception e){
	    		return false;
	    	}	
	    }
	    
	    public void updateDates(){
	    	
	    	// set the Gregorian version of LMD
	    	
	    	int ethioDay = 0;
	    	int ethioMonth = 0;
	    	int ethioYear = 0;
	    	try {
				ethioDay = Integer.parseInt(txtDay.getText().toString());
				ethioMonth = getArrayIndex(monthsArray, txtMonth.getText().toString()) +1;
				ethioYear = Integer.parseInt(txtYear.getText().toString());
	    	} catch (Exception e){
	    		return;
	    	}
	    	if(isValidDate(ethioDay,ethioMonth, ethioYear)){
		    	DateTime dt_eth = new DateTime(ethioYear, ethioMonth, ethioDay, 0, 0, 0, 0, chron_eth);
		    	// update the Gregorian date
		    	DateTime dtLMDGreg = dt_eth.withChronology(GregorianChronology.getInstance());
		    	DateTimeFormatter fmt = DateTimeFormat.forPattern("d MMMM yyyy");
		    	String str = fmt.print(dtLMDGreg);
		    	txtGregorian.setText("("+str+")");
		    
	    	}
	    }
	    
	private int getArrayIndex(String[] myArray, String myStr) {
		for (int i = 0; i < myArray.length; i++) {
			if (myArray[i].equals(myStr)) {
				return (i);
			}
		}
		return (-1);// didn't find what I was looking for
	}
}
